home *** CD-ROM | disk | FTP | other *** search
- page 60,132
- ;***********************************************************
- ;** **
- ;** Device Driver for RS232 communications **
- ;** TI PC Version **
- ;** Copyright (C) Texas Instruments 1986 **
- ;** Author: Greg Haley **
- ;** **
- ;** THIS SOURCE CODE MAY BE DISTRIBUTED AND MODIFIED **
- ;** ONLY IF THE ORIGINAL COPYRIGHT AND AUTHOR CREDITS **
- ;** REMAIN INTACT. **
- ;** **
- ;** Project Start Date: 11/20/86 **
- ;** **
- ;** RE: 12/29/86 by Greg Haley **
- ;** Added send_xon routine. **
- ;** Added TI internal modem support. **
- ;** Added 19200 baud. **
- ;** **
- ;***********************************************************
-
- name tirs232
- title Device Driver for TI PC Communications
-
- code segment byte
- assume cs:code,ds:nothing,es:nothing
-
- include rs232.inc
-
- page
- ;***********************************************************
- ;** Keyboard Routines **
- ;***********************************************************
- keyboard equ 4ah ; TI PC keyboard INT
- altah db 0 ; Storage for high byte of key input
-
- k_ready:
- mov al,cs:altah ; Get 2nd half of F-key?
- or al,al
- jnz k_rdy_xit ; Yes, skip to end
-
- mov ah,1 ; Is a char waiting?
- int keyboard
- jz k_rdy_xit ; No, exit
-
- or ax,ax ; If it was a ^C, remove it
- jnz k_rdy_xit
- xor ah,ah
- int keyboard
- jmp short k_ready ; And try again
-
- k_rdy_xit:
- ret
-
- k_read:
- xor ax,ax ; Clear AX
-
- xchg al,cs:altah ; Get 2nd half of F-key?
- or al,al
- jnz k_r_xit ; Yes, skip to end
-
- k_r_1:
- xor ah,ah
- int keyboard
-
- or ax,ax ; Was it a ^C?
- jz k_r_1 ; Yes, get another
-
- or al,al ; Is it a F-key?
- jnz k_r_xit ; No, exit
- mov cs:altah,ah ; Yes, save 2nd half
-
- k_r_xit:
- ret
-
- page
- ;***********************************************************
- ;** Communications Routines **
- ;***********************************************************
- recv_size equ 800h ; Receive buffer size
- ; Must be one of these values:
- ; 0004h = 4 bytes
- ; 0008h = 8 bytes
- ; 0010h = 16 bytes
- ; 0020h = 32 bytes
- ; 0040h = 64 bytes
- ; 0080h = 128 bytes
- ; 0100h = 256 bytes
- ; 0200h = 512 bytes
- ; 0400h = 1024 bytes
- ; 0800h = 2048 bytes
- ; 1000h = 4096 bytes
- ; 2000h = 8192 bytes
- ; 4000h = 16384 bytes
- ; 8000h = 32768 bytes
- recv_limit equ not recv_size ; Receive buffer limit mask
- busy_len equ recv_size *3 /4 ; Go busy at 3/4 buf length
- not_busy_len equ recv_size /2 ; Not busy at 1/2 buf length
-
- int_controller equ 19h ; 8259A Interrupt Controller port
- int_ack equ 18h ; 8259A Interrupt Acknowledge port
- EOI equ 00100000b ; Non-specific EOI
-
- enable_ints equ 01000000b ; Enable interrupts
- disable_ints equ 11000000b ; Disable interrupts
- dtr_bit equ 1 ; DTR bit in uart control register
- rts_bit equ 2 ; DTR bit in uart control register
- dcd_bit equ 1 ; DCD bit in modem status register
- cts_bit equ 2 ; CTS bit in modem status register
- dsr_bit equ 4 ; DSR bit in modem status register
- scf_bit equ 8 ; SCF bit in modem status register
- ri_bit equ 16 ; RI bit in modem status register
-
- xon equ 11h ; xmit on busy char
- xoff equ 13h ; xmit off busy char
-
- page
- ;***********************************************************
- ;** Variables **
- ;***********************************************************
-
- old_ss dw 0 ; Old SS reg
- old_sp dw 0 ; Old SP reg
- db 80 dup (?) ; Stack
- i_stack label byte
- rq_head dw 0 ; Receive Queue start
- rq_tail dw 0 ; Receive Queue stop
- rq_len dw 0 ; Current receive Queue length
- rqueue db recv_size dup (?) ; Receive queue
- oldseg dw 0 ; Old segment for int vector
- oldoff dw 0 ; Old offset for int vector
- busy_hand db 0 ; busy handling type
- r_busy db 0 ; recv busy flag
- t_busy db 0 ; xmit busy flag
- xmit_busy db 0 ; xmit busy flag (for ints)
- m_stat db 0 ; Current modem status
- l_stat db 0 ; Current line status
- dcw dw 1100000001010000b ; default 2400, 8, N, 1
- parity_on db 0 ; Parity flag
- ti_modem db 0 ; Flag for TI internal modem
-
- opn_tbl:
- db 0 ; Needs leading 0 for sync
- db 9 ; select reg 9
- db 01001001b ; Reset chan B, MIE, & VIS
- db 12 ; select reg 12
- baudl db 30 ; Low byte of baud rate (2400)
- db 13 ; select reg 13
- baudh db 0 ; High byte of baud rate
- db 2 ; select reg 2
- db 0 ; int vector on
- db 11 ; select reg 11
- db 01010010b ; brate generator
- db 14 ; select reg 14
- db 00000011b ; enable brate gen.
- db 4 ; select reg 4
- par_stp db 01000100b ; No parity, 1 stop bit
- db 3 ; select reg 3
- recv_b db 11000001b ; recv enable, 8 bits
- db 5 ; select reg 5
- xmit_b db 11101010b ; xmit enable, DTR, 8 bits
- db 10 ; select reg 10
- db 0 ; NRZ, flags
- db 15 ; select reg 15
- db 00101000b ; CTS, DCD int enable
- db 1 ; select reg 1
- db 00010111b ; int enable
- opn_size equ $-opn_tbl
-
- opn2_tbl:
- db 0 ; Sync byte
- db 15 ; select reg 15
- db 00101000b ; RI & DSR int enable
- db 1 ; select reg 1
- db 00000001b ; external int enable
- opn2_size equ $-opn2_tbl
-
- int_tbl dw 0 ; Interrupt branch table
- dw mod_stat
- dw 0
- dw 0
- dw xmit_mt
- dw mod_stat
- dw rec_full
- dw lin_stat
-
- ; table for baud rate constants
- baud_tbl dw 696 ; 110
- dw 510 ; 150
- dw 254 ; 300
- dw 126 ; 600
- dw 62 ; 1200
- dw 30 ; 2400
- dw 14 ; 4800
- dw 6 ; 9600
-
- ; table for port number init tables
- p_table dw port1_tbl
- dw port2_tbl
- dw port3_tbl
- dw port4_tbl
-
- port_n dw port1_tbl ; default port is 1
-
- ; port 1 init table
- port1_tbl dw 40h ; Interrupt vector for irq
- db 11111110b ; Mask to enable irq
- db 00000001b ; Mask to unable irq
- dw 0e7h ; Receive buffer port
- dw 0e7h ; Transmit buffer port
- dw 0e6h ; 8530 UART Control port
- dw 0e6h ; 8530 UART Status port
- dw 0e4h ; 8530 Modem Status port
- dw 0e6h ; 8530 interrupt enable register
- dw 0e0h ; 8530 interrupt ack register
- p_tbl_size equ $-port1_tbl
-
- ; port 2 init table
- port2_tbl dw 41h ; Interrupt vector for irq
- db 11111101b ; Mask to enable irq
- db 00000010b ; Mask to unable irq
- dw 0efh ; Receive buffer port
- dw 0efh ; Transmit buffer port
- dw 0eeh ; 8530 UART Control port
- dw 0eeh ; 8530 UART Status port
- dw 0ech ; 8530 Modem Status port
- dw 0eeh ; 8530 interrupt enable register
- dw 0e8h ; 8530 interrupt ack register
-
- ; port 3 init table
- port3_tbl dw 42h ; Interrupt vector for irq
- db 11111011b ; Mask to enable irq
- db 00000100b ; Mask to unable irq
- dw 0f7h ; Receive buffer port
- dw 0f7h ; Transmit buffer port
- dw 0f6h ; 8530 UART Control port
- dw 0f6h ; 8530 UART Status port
- dw 0f4h ; 8530 Modem Status port
- dw 0f6h ; 8530 interrupt enable register
- dw 0f0h ; 8530 interrupt ack register
-
- ; port 4 init table
- port4_tbl dw 44h ; Interrupt vector for irq
- db 11101111b ; Mask to enable irq
- db 00010000b ; Mask to unable irq
- dw 0ffh ; Receive buffer port
- dw 0ffh ; Transmit buffer port
- dw 0feh ; 8530 UART Control port
- dw 0feh ; 8530 UART Status port
- dw 0fch ; 8530 Modem Status port
- dw 0feh ; 8530 interrupt enable register
- dw 0f8h ; 8530 interrupt ack register
-
-
- ; defaults for port 1
- port_tbl label word
- comm1_vector dw 40h ; Interrupt vector for irq
- irq_enab_mask db 11111110b ; Mask to enable irq
- irq_unab_mask db 00000001b ; Mask to unable irq
- recv_buffer dw 0e7h ; Receive buffer port
- send_buffer dw 0e7h ; Transmit buffer port
- uart_control dw 0e6h ; 8530 UART Control port
- uart_status dw 0e6h ; 8530 UART Status port
- modem_status dw 0e4h ; 8530 Modem Status port
- int_enable dw 0e6h ; 8530 interrupt enable register
- ack_int dw 0e0h ; 8530 interrupt ack register
-
- page
- ;***********************************************************
- ;** Subroutine to set up comm chip per the DCW **
- ;** DCW is in AX **
- ;***********************************************************
- set_dcw:
- ; set parity type
- mov bl,al ; get low byte in BL
- and bl,00000011b ; mask unused bits
- and byte ptr par_stp,11111100b ; reset parity
- or byte ptr par_stp,bl ; change parity
- and bl,00000001b ; change parity flag
- mov byte ptr parity_on,bl ;
-
- ; set num stop bits
- mov bl,al ; get low byte in BL
- and bl,00001000b ; mask unused bits
- or bl,00000100b ; 1.5 stop bits not used
- and byte ptr par_stp,11110011b ; reset stop bits
- or byte ptr par_stp,bl ; change stop bits
-
- ; set baud rate
- mov bl,al ; get low byte in BL
- and bl,01110000b ; mask unused bits
- mov cl,3 ; shift to make word ptr
- shr bl,cl
- mov si,offset baud_tbl ; point to baud table
- xor bh,bh ; make BX a byte ptr
- add si,bx ; SI now points to baud rate const
- mov dx,word ptr [si] ; get baud rate in DX
- mov byte ptr baudl,dl ; save low byte of baud rate
- mov byte ptr baudh,dh ; save high byte of baud rate
-
- ; set busy type
- mov bl,ah
- and bl,00000011b ; mask unwanted bits
- mov byte ptr busy_hand,bl ; store it
-
- ; set port number
- mov bl,ah ; get high byte in BL
- and bl,00011000b ; mask unused bits
- shr bl,1 ; shift to make word ptr
- shr bl,1
- mov si,offset p_table ; point to port table
- xor bh,bh ; make BX a byte ptr
- add si,bx ; SI now points to baud rate const
- mov dx,word ptr [si] ; get port adrs in DX
- mov word ptr port_n,dx ; save port number adrs
-
- ; set data bits
- mov bl,ah ; get high byte in BL
- and bl,01000000b ; mask unused bits
- or bl,00100000b ; make it at least 7 bits
- and byte ptr xmit_b,10011111b ; reset xmit data size
- or byte ptr xmit_b,bl ; set xmit data size
- shl bl,1 ; adjust for recv data size
- and byte ptr recv_b,00111111b ; reset recv data size
- or byte ptr recv_b,bl ; set recv data size
-
- ; Check for internal modem
- mov ti_modem,al
- and ti_modem,00000100b ; TI internal modem if not 0
-
- ret
-
- page
- ;***********************************************************
- ;** Subroutine to set up interrupt vector **
- ;** and initialize the 8530 comm chip **
- ;***********************************************************
- init_comm:
- push ds
- push cs
- pop ds
-
- ; get correct port parameters
- push es
- push cs
- pop es
-
- mov si,word ptr port_n ; get port table adrs
- mov di,offset port_tbl ; DI points to table to use
- mov cx,p_tbl_size ; CX has table length
- repz movsb ; move it
-
- pop es
-
- ; Save old int vector for irq
- mov di,comm1_vector
- call get_vector
- mov word ptr oldseg,bx
- mov word ptr oldoff,dx
-
- ; Set up int vector for irq
- push cs ; Make BX = CS
- pop bx
- mov dx,offset isr
- mov di,comm1_vector
- call set_vector
-
- ; Enable irq from 8259A
- cli
- in al,int_controller
- jmp $+2 ; delay
- and al,irq_enab_mask
- out int_controller,al
-
- ; Read receive buffer register
- mov dx,recv_buffer
- in al,dx
-
- ; Read modem status register
- call mod_stat
-
- ; Read UART status register
- call lin_stat
-
- ; open 8530
- mov si,offset opn_tbl
- mov cx,opn_size
- mov dx,uart_control
- init_1:
- lodsb
- out dx,al
- jmp $+2 ; delay
- loop init_1
-
- mov si,offset opn2_tbl
- mov cx,opn2_size
- mov dx,modem_status
- init_2:
- lodsb
- out dx,al
- jmp $+2 ; delay
- loop init_2
-
- pop ds
- sti
-
- ; Reset TI internal modem if present
- cmp cs:byte ptr ti_modem,0 ; TI internal modem?
- jz no_ti_modem ; No, exit
- mov dx,modem_status ; Yes, set /RCNTL
- mov al,5
- out dx,al
- mov al,cs:xmit_b
- or al,2
- out dx,al
-
- wait_4_ack:
- mov dx,uart_status ; Check for ACK
- mov al,10h
- out dx,al
- jmp $+2 ; delay
- jmp $+2 ; delay
- in al,dx
- test al,10h ; Got an ACK?
- jz wait_4_ack ; No, keep looping
-
- no_ti_modem:
- ret
-
- page
- ;***********************************************************
- ;** Subroutine to restore interrupt vector **
- ;** and reset the 8530 comm chip **
- ;***********************************************************
- de_init:
- cli
-
- ; Disable interrupts on 8530 and drop DTR, RTS
- mov dx,cs: word ptr int_enable
- mov al,9 ; select reg 9
- out dx,al
- mov al,disable_ints
- jmp $+2 ; delay
- out dx,al
- jmp $+2 ; delay
- jmp $+2 ; delay
-
- ; Disable irq
- in al,int_controller
- or al,cs:byte ptr irq_unab_mask
- jmp $+2 ; delay
- jmp $+2 ; delay
- out int_controller,al
-
- ; It's probably not a good idea to restore the vector at close in
- ; this case, but here's the code to do it:
- ;
- ; Restore int vector for irq
- ; mov bx,cs:word ptr oldseg
- ; mov dx,cs:word ptr oldoff
- ; mov di,comm1_vector
- ; call set_vector
- sti
- ret
-
- page
- ;***********************************************************
- ;** Interrupt Service Routine **
- ;***********************************************************
- isr:
- cli
- cld
- ; Set up new stack
- mov cs:word ptr old_sp,sp
- mov cs:word ptr old_ss,ss
- mov sp,cs
- mov ss,sp
- mov sp,offset i_stack
-
- push ax
- push bx
- push cx
- push dx
- push ds
-
- push cs
- pop ds
-
- ; Verify int came from 8530
- mov dx,uart_status
- mov al,3 ; reg 3
- out dx,al ; select reg 3
- jmp $+2 ; delay
- jmp $+2 ; delay
- in al,dx ; read reg 3
- or al,al ; Interrupt pending?
- jz isr_exit ; No, exit
-
- ; Acknowledge int
- mov dx,ack_int ; get int ack reg
- xor al,al ; 1st write a 0
- out dx,al
- jmp $+2 ; delay
- jmp $+2 ; delay
- in al,dx ; get int type
-
- ; Branch to correct routine
- cbw ; make int type a word
- mov bx,offset int_tbl ; point to int table
- add bx,ax ; add int type
- sti
- call cs:word ptr [bx] ; go do subroutine
- cli
-
- ; Reset highest int under service by 8530
- mov al,00111000b ; reset highest int code
- mov dx,int_enable ; select port
- out dx,al ; reset the int
- jmp $+2 ; delay
-
- isr_exit:
- ; Tell 8259A we're done
- mov al,EOI
- out int_ack,al
-
- pop ds
- pop dx
- pop cx
- pop bx
- pop ax
-
- ; restore stack
- mov ss,cs:word ptr old_ss
- mov sp,cs:word ptr old_sp
-
- sti
- iret
-
- page
- ;***********************************************************
- ;** Subroutine to read the modem status **
- ;***********************************************************
- mod_stat:
- mov dx,modem_status ; Read modem status (CHB)
- xor al,al ; reg 0
- out dx,al ; Select reg 0
- jmp $+2 ; delay
- jmp $+2 ; delay
- in al,dx ; read reg 0
- mov cl,5 ; move bits to AH
- shl ax,cl
- xor al,al ; Read reg 0
- mov dx,modem_status ; Read modem status (CHB)
- inc dx ; adjust to channel A
- inc dx
- out dx,al ; Select reg 0
- jmp $+2 ; delay
- jmp $+2 ; delay
- in al,dx ; into reg AL
-
- shl al,1 ; adjust to match ACS lib
- shl al,1
- shl ax,1
- shl al,1
- shl ax,1
- and ah,00011111b ; mask unwanted bits
-
- ; AH now contains the line signals
- ; ---------------------------------
- ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- ; ---------------------------------
- ; | | | | RI|SCF|DSR|CTS|DCD|
- ; ---------------------------------
- ; 0=down, 1=up
-
- mov cs:byte ptr m_stat,ah ; Update current modem status
-
- ; Check for busy handling
- shr ah,1 ; DSR in bit 0
- shr ah,1
- cmp cs:byte ptr busy_hand,2 ; DSR busy handling?
- jne chk_4scf ; No, skip
- mov al,ah ; save AH
- jmp set_tbusy ; go set or reset busy
- chk_4scf:
- cmp cs:byte ptr busy_hand,1 ; SCF busy handling?
- jne rst_sts ; No, skip
- shr ah,1
- mov al,ah ; save AH
- set_tbusy:
- and al,1 ; up = busy on
- ; not al ; down = busy on
- mov cs:byte ptr t_busy,al ; set busy
-
-
- ; reset ext stat int
- rst_sts:
- mov al,10h ; reset ext sts code
- mov dx,modem_status ; reset chan B
- out dx,al
- jmp $+2 ; delay
- mov dx,uart_control ; reset chan A
- out dx,al
-
- ret
-
- page
- ;***********************************************************
- ;** Subroutine to send the next char in queue **
- ;***********************************************************
- xmit_mt:
- mov cs:byte ptr xmit_busy,0 ; We're not busy
-
- ; reset xmit int
- mov al,00101000b ; code
- mov dx,uart_control
- out dx,al
-
- ret
-
- page
- ;***********************************************************
- ;** Subroutine to receive a char and queue it **
- ;***********************************************************
- rec_full:
- mov dx,recv_buffer ; Get char
- in al,dx
- cmp cs:byte ptr parity_on,0 ; parity?
- jz no_par ; No, don't mask off parity bit
- and al,7fh ; Yes, mask off parity bit
- no_par:
- ; check for XON-XOFF busy char
- cmp cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
- jne queue_char ; No, skip busy handling
- cmp al,xoff ; Need to set busy?
- jne chk_r_xon ; No, skip
- mov cs:byte ptr t_busy,1 ; set busy
- jmp xit_rec_full ; We're done
-
- chk_r_xon:
- cmp al,xon ; Need to reset busy?
- jne queue_char ; No, skip busy handling
- mov cs:byte ptr t_busy,0 ; reset busy
- jmp xit_rec_full ; We're done
-
- queue_char:
- ; check for buffer overflow
- cmp cs:word ptr rq_len,recv_limit ; buffer full?
- jb buf_full1 ; No, skip
- inc cs:word ptr rq_tail ; Yes, lose 1 char
- and cs:word ptr rq_tail,recv_limit
- dec cs:word ptr rq_len ; Adjust queue length
- buf_full1:
-
- mov bx,offset rqueue ; Queue char
- mov dx,cs:word ptr rq_head
- add bx,dx
- mov cs:byte ptr [bx],al
- inc dx
- and dx,recv_limit ; wrap if >= receive size
- mov cs:word ptr rq_head,dx
- inc cs:word ptr rq_len ; Adjust queue length
-
- ; set busy if needed
- cmp cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
- jne set_rb_done ; No, skip
- cmp cs:word ptr rq_len,busy_len ; Need to set busy?
- jb set_rb_done ; No, skip
- mov cs:byte ptr r_busy,1 ; set busy flag
- mov dx,cs:word ptr send_buffer ; send XOFF char
- mov al,xoff
- out dx,al
- set_rb_done:
-
- xit_rec_full:
- ret
-
- page
- ;***********************************************************
- ;** Subroutine to send an xon char if needed **
- ;***********************************************************
- send_xon:
- cmp cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
- jne xit_send_xon ; No, skip
- mov dx,cs:word ptr send_buffer ; send XON char
- mov al,xon
- out dx,al
-
- xit_send_xon:
- ret
-
- page
- ;***********************************************************
- ;** Subroutine to read the line status **
- ;***********************************************************
- lin_stat:
- mov dx,uart_status
- mov al,1 ; select reg 1
- out dx,al
- jmp $+2 ; delay
- jmp $+2 ; delay
- in al,dx ; read status
- mov cs:byte ptr l_stat,al ; Update current line status
-
- ; reset error
- mov al,00110000b ; reset lin stat error code
- out dx,al
-
- ret
-
- page
- ;***********************************************************
- ;** Subroutine to get an interrupt vector **
- ;** **
- ;** di = vector number **
- ;** **
- ;** Return: **
- ;** bx = segment **
- ;** dx = offset **
- ;***********************************************************
- get_vector:
- push es
- xor ax,ax
- mov es,ax
- shl di,1
- shl di,1
- mov dx,es:word ptr[di]
- mov bx,es:word ptr[di+2]
- pop es
- ret
-
- page
- ;***********************************************************
- ;** Subroutine to set an interrupt vector **
- ;** **
- ;** di = vector number **
- ;** bx = segment **
- ;** dx = offset **
- ;***********************************************************
- set_vector:
- push es
- xor ax,ax
- mov es,ax
- shl di,1
- shl di,1
- mov es:word ptr[di],dx
- mov es:word ptr[di+2],bx
- pop es
- ret
-
-
- page
- ;***********************************************************
- ;** Everything past here is truncated after install **
- ;***********************************************************
-
- init proc near
- lds bx,cs:[ptrsav]
- mov word ptr [bx].trans,offset init ;set break address
- mov [bx].trans+2,cs
-
- print_init:
- push cs
- pop ds
- mov dx,offset init_msg
- mov ah,9
- int 21h
-
- jmp exit
- init endp
-
- init_msg:
- db cr,lf,'TI PC Communications Driver v2.51'
- db ' Copyright (C) Texas Instruments 1986'
- db cr,lf,'Written by '
- db 'Greg Haley'
- db cr,lf,cr,lf,'$'
- code ends
- end
-